/**
 *@note Copyright 2012-2022 CETHIK All Rights Reserved.
 *@brief  配置文件读入功能类文件
 *@author tuyinan
 *@data 2022-04-xx
 */

#ifndef CONFIG_FILE_H_
#define CONFIG_FILE_H_

#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <typeinfo>
#include <vector>

/**
 *@brief 配置文件读入功能类
 *@author tuyinan
 *@version 2022-04-xx
 */
class ConfigFile {
 public:
  /**
   *@brief 初始化
   *@param const string& fName 参数文件地址
   *@return void
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  ConfigFile(const std::string &fName);
  /**
   *@brief 解析出关键字和对应值
   *@param 无
   *@return bool 'false'代表没有配置文件，'true'代表ok
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  bool ExtractKeys();
  /**
   *@brief 查看关键字是否存在
   *@param const string& key 关键字
   *@return bool 'false'代表没有，'true'代表有
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  bool keyExists(const std::string &key) const;
  /**
   *@brief 根据关键字获取数字类值
   *@param const string& key 关键字
   *@param ValueType const &defaultValue 默认数值
   *@return ValueType 对应的数值
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  template <typename ValueType>
  ValueType getValueOfKey(const std::string &key,
                          ValueType const &defaultValue) const {
    if (!keyExists(key)) {return defaultValue;}

    return string_to_T<ValueType>(contents.find(key)->second);
  }
  /**
   *@brief 根据关键字取string类型的值
   *@param const string& key 关键字
   *@param const string& defaultValue 默认数值
   *@return string 对应的数值
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  std::string getValueOfKeyAsString(const std::string &key,
                                    const std::string &defaultValue);
  /**
   *@brief 根据关键字取double类型数组
   *@param const string& key 关键字
   *@param const string& defaultValue 默认数值
   *@return std::vector<double> 对应的数组
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  std::vector<double> getValueOfKeyAsStdVectorDouble(
      const std::string &key, const std::string &defaultValue);
  /**
   *@brief 根据关键字取int类型数组
   *@param const string& key 关键字
   *@param const string& defaultValue 默认数值
   *@return std::vector<int> 对应的数组
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  std::vector<int> getValueOfKeyAsStdVectorInt(const std::string &key,
                                               const std::string &defaultValue);
  /**
   *@brief 转换数据类型到string
   *@param T const& val 要转换的数据
   *@return string 转换后的string
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  template <typename T>
  std::string T_to_string(T const &val) const {
    std::ostringstream ostr;
    ostr << val;

    return ostr.str();
  }
  /**
   *@brief 转换string类型数据到任意类型
   *@param string const &val 要转换的string类型数据
   *@return T 转换后的类型值
   *@author: tuyinan
   *@version: 2022-04-xx
   */
  template <typename T>
  T string_to_T(std::string const &val) const {
    std::istringstream istr(val);
    T returnVal;
    istr >> std::boolalpha >> returnVal;
    // if (!(istr >> returnVal))
    //   std::cout << "CFG: Not a valid " + (std::string) typeid(T).name() +
    //                    " received!\n";
    return returnVal;
  }

 private:
/**
*@brief 移除字段中的注释
*@param string& line 原字段
*@return void
*@author: tuyinan
*@version: 2022-04-xx
*/
  void removeComment(std::string &line) const;
/**
*@brief 判断字段是否只有空格
*@param string& line 原字段
*@return bool 'true'为yes，'false'no
*@author: tuyinan
*@version: 2022-04-xx
*/
  bool onlyWhitespace(const std::string &line) const;
/**
*@brief 判断字段是否符合编写规范
*@param const string& line 原字段
*@return bool 'true'为yes，'false'no
*@author: tuyinan
*@version: 2022-04-xx
*/
  bool validLine(const std::string &line) const;
/**
*@brief 字段中提取关键字
*@param string& key 关键字
*@param size_t const& sepPos 断点
*@param const string& line 原字段
*@return void
*@author: tuyinan
*@version: 2022-04-xx
*/
  void extractKey(std::string &key, size_t const &sepPos,
                  const std::string &line) const;
/**
*@brief 字段中提取数值
*@param string& value 数值
*@param size_t const& sepPos 断点
*@param const string& line 原字段
*@return void
*@author: tuyinan
*@version: 2022-04-xx
*/
  void extractValue(std::string &value, size_t const &sepPos,
                    const std::string &line) const;
/**
*@brief 提取字段
*@param const string& line 原字段
*@return void
*@author: tuyinan
*@version: 2022-04-xx
*/
  void extractContents(const std::string &line);
/**
*@brief 根据符号“=”分段
*@param const string& line 原字段
*@param size_t const lineNo 字段编号
*@return void
*@author: tuyinan
*@version: 2022-04-xx
*/
  void parseLine(const std::string &line, size_t const lineNo);
/**
*@brief string类型转double
*@param const string& str
*@return std::vector<double> 返回的数值
*@author: tuyinan
*@version: 2022-04-xx
*/
  std::vector<double> stringToDouble(const std::string &str);
/**
*@brief string类型转int
*@param const string& str
*@return std::vector<int> 返回的数值
*@author: tuyinan
*@version: 2022-04-xx
*/
  std::vector<int> stringToInt(const std::string &str);
  /// 内容存储空间
  std::map<std::string, std::string> contents;
  /// 文件名
  std::string fName;
};

#endif /* CONFIG_FILE_H_ */
